package com.sky.controller.admin;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import cn.mybatis.mp.core.mybatis.mapper.context.Pager;
import com.sky.constant.MessageConstant;
import com.sky.constant.RedisKeyConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.Admins;
import com.sky.exception.BaseException;
import com.sky.result.Result;
import com.sky.service.AdminUserService;
import com.sky.service.UserBanService;
import com.sky.vo.AdminLoginVO;
import com.sky.vo.AdminUserPageVO;
import com.sky.vo.UserPageVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Collections;
import java.util.List;

/**
 * 用户管理相关接口
 */
@Slf4j
@RestController
@RequestMapping("/admin")
public class AdminUserManageController {

    @Autowired
    private AdminUserService adminUserService;

    @Autowired
    private UserBanService userBanService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 管理员登录
     *
     * @param loginDTO 登录表单
     * @return adminToken
     * @权限 all
     */
    @SaIgnore
    @PostMapping("/login")
    public Result<AdminLoginVO> adminLogin(@RequestBody LoginDTO loginDTO) {

        log.info("管理员登录：{}", loginDTO);

        AdminLoginVO adminLogin = adminUserService.adminLogin(loginDTO);

        return Result.success(adminLogin);

    }

    /**
     * 管理端获取用户列表(包含封禁信息)
     *
     * @param queryDTO 查询条件，包含：
     *                - username: 用户名（可选）
     *                - email: 邮箱（可选）
     *                - status: 用户状态（可选，0-正常，1-封禁）
     *                - page: 页码（必选）
     *                - pageSize: 每页大小（必选）
     * @return 用户分页数据
     */
    @PostMapping("/users")
    @SaCheckPermission(value = "UserManagementRelated", orRole = {"SuperAdmin", "UserAdmin"})
    public Result<Pager<UserPageVO>> getUserList(@RequestBody UserPageQueryDTO queryDTO) {
        log.info("获取用户列表: {}", queryDTO);

        // 参数校验
        if (queryDTO.getPage() == null || queryDTO.getPageSize() == null) {
            return Result.error("分页参数不能为空");
        }

        // 调用服务查询数据
        Pager<UserPageVO> pager = userBanService.getUsersPage(queryDTO);

        return Result.success(pager);

    }

    /**
     * 分页获取管理员账户列表分页获取管理员账户列表
     *
     * @param queryDTO 查询条件，包含：
     *                - page: 页码（必填）
     *                - pageSize: 每页数量（必填）
     *                - username: 管理员用户名（可选）
     *                - email: 邮箱（可选）
     *                - role: 角色ID（可选）
     *                - status: 状态（可选）
     * @return 管理员账户分页数据
     */
    @PostMapping("/adminUsers")
    @SaCheckPermission(value = "adminUser", orRole = {"SuperAdmin"})
    public Result<Pager<AdminUserPageVO>> getAdminUserList(@RequestBody AdminUserPageQueryDTO queryDTO) {
        log.info("获取管理员账户列表: {}", queryDTO);

        // 参数校验
        if (queryDTO.getPage() == null || queryDTO.getPageSize() == null) {
            return Result.error("分页参数不能为空");
        }

        // 调用服务查询数据
        Pager<AdminUserPageVO> pager = adminUserService.getAdminUsersPage(queryDTO);

        return Result.success(pager);
    }

    /**
     * 修改管理员信息
     *
     * @param adminUserUpdateDTO 管理员信息
     * @return Result
     */
    @PutMapping("/adminUser")
    @SaCheckPermission(value = "adminUser", orRole = {"SuperAdmin"})
    public Result updateAdminUser(@RequestBody @Valid AdminUserUpdateDTO adminUserUpdateDTO) {
        log.info("修改管理员信息：{}", adminUserUpdateDTO);

        // 构建Admins对象
        Admins admin = new Admins();
        admin.setAdminId(adminUserUpdateDTO.getId());
        admin.setUsername(adminUserUpdateDTO.getUsername());
        admin.setEmail(adminUserUpdateDTO.getEmail());

        // 构建角色ID列表
        List<Integer> roleIds = Collections.singletonList(adminUserUpdateDTO.getRole());

        // 调用服务更新管理员信息
        adminUserService.updateAdmin(admin, roleIds);

        return Result.success();
    }

    /**
     * 修改管理员账户状态
     *
     * @param adminUserStatusDTO 状态信息
     * @return Result
     */
    @PutMapping("/adminUser/status")
    @SaCheckPermission(value = "adminUser", orRole = {"SuperAdmin"})
    public Result updateAdminStatus(@RequestBody @Valid AdminUserStatusDTO adminUserStatusDTO) {
        log.info("修改管理员账户状态：{}", adminUserStatusDTO);

        // 调用服务更新管理员状态
        adminUserService.updateStatus(adminUserStatusDTO.getId(), adminUserStatusDTO.getStatus());

        return Result.success();
    }

    /**
     * 新增管理员
     * 创建一个新的管理员账户，包括：
     * 1. 设置基本信息（用户名、邮箱）
     * 2. 设置安全信息（密码）
     * 3. 分配角色权限
     * 4. 设置账户状态
     *
     * 说明：
     * - 用户名不允许重复
     * - 密码会进行加密存储
     * - 默认状态为启用(0)
     * - 需要超级管理员权限
     *
     * @param adminUserCreateDTO 管理员信息，包含：
     *                          - username: 用户名（必填，3-20字符）
     *                          - email: 邮箱地址（必填，需符合邮箱格式）
     *                          - password: 密码（必填，6-20字符）
     *                          - role: 角色ID（必填）
     *                          - status: 状态（可选，默认0-启用）
     * @return Result 统一响应结果
     */
    @PostMapping("/createAdminUser")
    @SaCheckPermission(value = "adminUser", orRole = {"SuperAdmin"})
    public Result createAdminUser(@RequestBody @Valid AdminUserCreateDTO adminUserCreateDTO) {
        log.info("新增管理员：{}", adminUserCreateDTO);

        // 构建Admins对象
        Admins admin = new Admins();
        admin.setUsername(adminUserCreateDTO.getUsername());
        admin.setEmail(adminUserCreateDTO.getEmail());
        admin.setPassword(adminUserCreateDTO.getPassword());
        admin.setStatus(adminUserCreateDTO.getStatus());

        // 构建角色ID列表
        List<Integer> roleIds = Collections.singletonList(adminUserCreateDTO.getRole());

        // 调用服务创建管理员
        adminUserService.createAdmin(admin, roleIds);

        return Result.success();
    }

    /**
     * 删除管理员账户
     * 说明：
     * 1. 需要超级管理员权限
     * 2. 需要验证码验证
     * 3. 删除后该管理员所有权限将被撤销
     * 4. 删除后该管理员token将失效
     *
     * @param adminUserDeleteDTO 删除信息，包含：
     *                          - id: 管理员ID
     *                          - verificationCode: 验证码
     * @return Result 统一响应结果
     */
    @DeleteMapping("/adminUser/{id}")
    @SaCheckPermission(value = "adminUser", orRole = {"SuperAdmin"})
    public Result deleteAdminUser(@PathVariable Integer id, @RequestBody @Valid AdminUserDeleteDTO adminUserDeleteDTO) {
        log.info("删除管理员账户：{}", id);

        try {
            // 校验ID一致性
            if (!id.equals(adminUserDeleteDTO.getId())) {
                return Result.error("参数不一致");
            }

            // 获取当前管理员ID
            Integer currentAdminId = StpUtil.getLoginIdAsInt();

            // 不能删除自己的账户
            if (id.equals(currentAdminId)) {
                return Result.error("不能删除自己的账户");
            }

            // 验证验证码
            String redisKey = RedisKeyConstant.ADMIN_DELETE_ADMIN_CODE + currentAdminId + ":" + id;
            String storedCode = (String) redisTemplate.opsForValue().get(redisKey);

            if (storedCode == null) {
                return Result.error(MessageConstant.VERIFICATION_CODE_EXPIRED);
            }

            if (!storedCode.equals(adminUserDeleteDTO.getVerificationCode())) {
                return Result.error(MessageConstant.VERIFICATION_CODE_ERROR);
            }

            // 验证通过，删除验证码
            redisTemplate.delete(redisKey);

            // 强制目标管理员下线
            StpUtil.kickout(id);

            // 调用服务删除管理员账户
            adminUserService.deleteAdmin(id);

            return Result.success();
        } catch (Exception e) {
            log.error("删除管理员账户失败：", e);
            return Result.error("删除管理员账户失败：" + e.getMessage());
        }
    }

    /**
     * 获取当前登录管理员的个人资料
     * 说明：
     * 1. 需要管理员登录权限
     * 2. 返回当前登录管理员的用户名和邮箱信息
     *
     * @return Result 统一响应结果，包含管理员基本信息
     */
    @GetMapping("/profile")
    public Result<Admins> getAdminProfile() {
        log.info("获取管理员个人资料");
        
        // 获取当前登录的管理员ID
        Integer adminId = StpUtil.getLoginIdAsInt();
        
        // 调用服务获取管理员信息
        Admins admin = adminUserService.getAdminById(adminId);
        
        return Result.success(admin);
    }

    /**
     * 更新当前登录管理员的个人资料
     * 说明：
     * 1. 需要管理员登录权限
     * 2. 只能更新自己的资料
     * 3. 用户名不能与其他管理员重复
     *
     * @param profileUpdateDTO 更新的资料信息
     * @return Result 统一响应结果
     */
    @PutMapping("/profile")
    public Result updateAdminProfile(@RequestBody @Valid AdminProfileUpdateDTO profileUpdateDTO) {
        log.info("更新管理员个人资料：{}", profileUpdateDTO);

        if (profileUpdateDTO.getUsername() == null || profileUpdateDTO.getEmail() == null) {
            throw new BaseException(MessageConstant.THE_SUBMISSION_CANNOT_BE_EMPTY);
        }
        
        // 获取当前登录的管理员ID
        Integer adminId = StpUtil.getLoginIdAsInt();
        
        // 构建Admins对象
        Admins admin = new Admins();
        admin.setAdminId(adminId);
        admin.setUsername(profileUpdateDTO.getUsername());
        admin.setEmail(profileUpdateDTO.getEmail());
        
        // 调用服务更新管理员信息
        adminUserService.adminUpdateAdmin(admin);
        
        return Result.success();
    }

    /**
     * 修改当前登录管理员的密码
     * 说明：
     * 1. 需要管理员登录权限
     * 2. 需要验证当前密码
     * 3. 新密码不能与当前密码相同
     * 4. 密码修改成功后需要重新登录
     *
     * @param passwordUpdateDTO 密码修改信息
     * @return Result 统一响应结果
     */
    @PostMapping("/password")
    public Result updateAdminPassword(@RequestBody @Valid AdminPasswordUpdateDTO passwordUpdateDTO) {
        log.info("修改管理员密码");

        if (passwordUpdateDTO.getOldPassword() == null || passwordUpdateDTO.getNewPassword() == null) {
            throw new BaseException(MessageConstant.THE_SUBMISSION_CANNOT_BE_EMPTY);
        }
        
        // 获取当前登录的管理员ID
        Integer adminId = StpUtil.getLoginIdAsInt();
        
        // 调用服务修改密码
        adminUserService.updatePassword(adminId, passwordUpdateDTO.getOldPassword(), passwordUpdateDTO.getNewPassword());
        
        // 密码修改成功后，强制用户重新登录
        StpUtil.logout();
        
        return Result.success();
    }
} 